home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_thread.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  7KB  |  288 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23. #ifdef SAVE_RCSID
  24. static char rcsid =
  25.  "@(#) $Id: SDL_thread.c,v 1.1.2.2 2001/02/10 07:20:04 hercules Exp $";
  26. #endif
  27.  
  28. /* System independent thread management routines for SDL */
  29.  
  30. #include <stdio.h>
  31. #include <stdlib.h>
  32. #include <string.h>
  33.  
  34. #include "SDL_error.h"
  35. #include "SDL_mutex.h"
  36. #include "SDL_thread.h"
  37. #include "SDL_thread_c.h"
  38. #include "SDL_systhread.h"
  39.  
  40. #define ARRAY_CHUNKSIZE    32
  41. /* The array of threads currently active in the application
  42.    (except the main thread)
  43.    The manipulation of an array here is safer than using a linked list.
  44. */
  45. static int SDL_maxthreads = 0;
  46. static int SDL_numthreads = 0;
  47. static SDL_Thread **SDL_Threads = NULL;
  48. static struct SignalSemaphore thread_lock;
  49. int thread_lock_created = 0;
  50.  
  51. int SDL_ThreadsInit(void)
  52. {
  53.     InitSemaphore(&thread_lock);
  54.     thread_lock_created=1;
  55.     return 0;
  56. }
  57.  
  58. /* This should never be called...
  59.    If this is called by SDL_Quit(), we don't know whether or not we should
  60.    clean up threads here.  If any threads are still running after this call,
  61.    they will no longer have access to any per-thread data.
  62.  */
  63. void SDL_ThreadsQuit()
  64. {
  65.     thread_lock_created=0;
  66. }
  67.  
  68. /* Routines for manipulating the thread list */
  69. static void SDL_AddThread(SDL_Thread *thread)
  70. {
  71.     SDL_Thread **threads;
  72.  
  73.     /* WARNING:
  74.        If the very first threads are created simultaneously, then
  75.        there could be a race condition causing memory corruption.
  76.        In practice, this isn't a problem because by definition there
  77.        is only one thread running the first time this is called.
  78.     */
  79.     if ( !thread_lock_created ) {
  80.         if ( SDL_ThreadsInit() < 0 ) {
  81.             return;
  82.         }
  83.     }
  84.     ObtainSemaphore(&thread_lock);
  85.  
  86.     /* Expand the list of threads, if necessary */
  87. #ifdef DEBUG_THREADS
  88.     printf("Adding thread (%d already - %d max)\n",
  89.             SDL_numthreads, SDL_maxthreads);
  90. #endif
  91.     if ( SDL_numthreads == SDL_maxthreads ) {
  92.         threads=(SDL_Thread **)malloc((SDL_maxthreads+ARRAY_CHUNKSIZE)*
  93.                                       (sizeof *threads));
  94.         if ( threads == NULL ) {
  95.             SDL_OutOfMemory();
  96.             goto done;
  97.         }
  98.         memcpy(threads, SDL_Threads, SDL_numthreads*(sizeof *threads));
  99.         SDL_maxthreads += ARRAY_CHUNKSIZE;
  100.         if ( SDL_Threads ) {
  101.             free(SDL_Threads);
  102.         }
  103.         SDL_Threads = threads;
  104.     }
  105.     SDL_Threads[SDL_numthreads++] = thread;
  106. done:
  107.     ReleaseSemaphore(&thread_lock);
  108. }
  109.  
  110. static void SDL_DelThread(SDL_Thread *thread)
  111. {
  112.     int i;
  113.  
  114.     if ( thread_lock_created ) {
  115.         ObtainSemaphore(&thread_lock);
  116.         for ( i=0; i<SDL_numthreads; ++i ) {
  117.             if ( thread == SDL_Threads[i] ) {
  118.                 break;
  119.             }
  120.         }
  121.         if ( i < SDL_numthreads ) {
  122.             --SDL_numthreads;
  123.             while ( i < SDL_numthreads ) {
  124.                 SDL_Threads[i] = SDL_Threads[i+1];
  125.                 ++i;
  126.             }
  127. #ifdef DEBUG_THREADS
  128.             printf("Deleting thread (%d left - %d max)\n",
  129.                     SDL_numthreads, SDL_maxthreads);
  130. #endif
  131.         }
  132.         ReleaseSemaphore(&thread_lock);
  133.     }
  134. }
  135.  
  136. /* The default (non-thread-safe) global error variable */
  137. static SDL_error SDL_global_error;
  138.  
  139. /* Routine to get the thread-specific error variable */
  140. SDL_error *SDL_GetErrBuf(void)
  141. {
  142.     SDL_error *errbuf;
  143.  
  144.     errbuf = &SDL_global_error;
  145.     if ( SDL_Threads ) {
  146.         int i;
  147.         Uint32 this_thread;
  148.  
  149.         this_thread = SDL_ThreadID();
  150.         ObtainSemaphore(&thread_lock);
  151.         for ( i=0; i<SDL_numthreads; ++i ) {
  152.             if ( this_thread == SDL_Threads[i]->threadid ) {
  153.                 errbuf = &SDL_Threads[i]->errbuf;
  154.                 break;
  155.             }
  156.         }
  157.         ReleaseSemaphore(&thread_lock);
  158.     }
  159.     return(errbuf);
  160. }
  161.  
  162.  
  163. /* Arguments and callback to setup and run the user thread function */
  164. typedef struct {
  165.     int (*func)(void *);
  166.     void *data;
  167.     SDL_Thread *info;
  168.     struct Task *wait;
  169. } thread_args;
  170.  
  171. void SDL_RunThread(void *data)
  172. {
  173.     thread_args *args;
  174.     int (*userfunc)(void *);
  175.     void *userdata;
  176.     int *statusloc;
  177.  
  178.     /* Perform any system-dependent setup
  179.        - this function cannot fail, and cannot use SDL_SetError()
  180.      */
  181.     SDL_SYS_SetupThread();
  182.  
  183.     /* Get the thread id */
  184.     args = (thread_args *)data;
  185.     args->info->threadid = SDL_ThreadID();
  186.  
  187.     /* Figure out what function to run */
  188.     userfunc = args->func;
  189.     userdata = args->data;
  190.     statusloc = &args->info->status;
  191.  
  192.     /* Wake up the parent thread */
  193.     Signal(args->wait,SIGBREAKF_CTRL_E);
  194.  
  195.     /* Run the function */
  196.     *statusloc = userfunc(userdata);
  197. }
  198.  
  199. SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
  200. {
  201.     SDL_Thread *thread;
  202.     thread_args *args;
  203.     int ret;
  204.  
  205.     /* Allocate memory for the thread info structure */
  206.     thread = (SDL_Thread *)malloc(sizeof(*thread));
  207.     if ( thread == NULL ) {
  208.         SDL_OutOfMemory();
  209.         return(NULL);
  210.     }
  211.     memset(thread, 0, (sizeof *thread));
  212.     thread->status = -1;
  213.  
  214.     /* Set up the arguments for the thread */
  215.     args = (thread_args *)malloc(sizeof(*args));
  216.     if ( args == NULL ) {
  217.         SDL_OutOfMemory();
  218.         free(thread);
  219.         return(NULL);
  220.     }
  221.     args->func = fn;
  222.     args->data = data;
  223.     args->info = thread;
  224.     args->wait = FindTask(NULL);
  225.     if ( args->wait == NULL ) {
  226.         free(thread);
  227.         free(args);
  228.         SDL_OutOfMemory();
  229.         return(NULL);
  230.     }
  231.  
  232.     /* Add the thread to the list of available threads */
  233.     SDL_AddThread(thread);
  234.  
  235.     D(bug("Starting thread...\n"));
  236.  
  237.     /* Create the thread and go! */
  238.     ret = SDL_SYS_CreateThread(thread, args);
  239.     if ( ret >= 0 ) {
  240.         D(bug("Waiting for thread CTRL_E...\n"));
  241.         /* Wait for the thread function to use arguments */
  242.         Wait(SIGBREAKF_CTRL_E);
  243.         D(bug("  Arrived."));
  244.     } else {
  245.         /* Oops, failed.  Gotta free everything */
  246.         SDL_DelThread(thread);
  247.         free(thread);
  248.         thread = NULL;
  249.     }
  250.     free(args);
  251.  
  252.     /* Everything is running now */
  253.     return(thread);
  254. }
  255.  
  256. void SDL_WaitThread(SDL_Thread *thread, int *status)
  257. {
  258.     if ( thread ) {
  259.         SDL_SYS_WaitThread(thread);
  260.         if ( status ) {
  261.             *status = thread->status;
  262.         }
  263.         SDL_DelThread(thread);
  264.         free(thread);
  265.     }
  266. }
  267.  
  268. Uint32 SDL_GetThreadID(SDL_Thread *thread)
  269. {
  270.     Uint32 id;
  271.  
  272.     if ( thread ) {
  273.         id = thread->threadid;
  274.     } else {
  275.         id = SDL_ThreadID();
  276.     }
  277.     return(id);
  278. }
  279.  
  280. void SDL_KillThread(SDL_Thread *thread)
  281. {
  282.     if ( thread ) {
  283.         SDL_SYS_KillThread(thread);
  284.         SDL_WaitThread(thread, NULL);
  285.     }
  286. }
  287.  
  288.